use core::ptr;

use ch32l1::ch32l103::{gpioa::cfglr, Peripherals};
use ch32l1_macro::{proc_macro_dosome, proc_macro_mygpio};
use embedded_hal::digital::OutputPin;

const R_GPIO_CFGR_BASEADDR: u32 = 0x40010800;
extern crate bit_field;
use bit_field::BitField;

pub enum CNF {
    AnalogInput = 0b00,
    FloatingInput = 0b01,
    UpDownInput = 0b10,
}

// #[repr(u8)]
pub enum MODE {
    Input = 0b00,
    Mhz10 = 0b01,
    MHz2 = 0b10,
    MHz50 = 0b11,
}

pub struct GPIO<'a, const G: char, const N: u8> {
    periperals: &'a Peripherals,
    cfgr: *mut u32,
    cfgr_offset: usize,
    outdr: *mut u16,
}

impl<'a, const G: char, const N: u8> GPIO<'a, G, N> {
    pub fn get(periperals: &'a Peripherals) -> Self {
        let l_r_offset: u32 = if N > 7 { 4 } else { 0 };
        let g_offset: u32;
        let outdr: u32;
        match G {
            'A' => {
                g_offset = 0x40010800;
                outdr = 0x4001080C;
            }
            'B' => {
                g_offset = 0x40010C00;
                outdr = 0x40010C0C;
            }
            'C' => {
                g_offset = 0x40011000;
                outdr = 0x4001100C;
            }
            'D' => {
                g_offset = 0x40011400;
                outdr = 0x4001140C;
            }
            _ => {
                panic!("GPIO not support")
            }
        };
        let cfgr = g_offset + l_r_offset;

        GPIO {
            periperals,
            cfgr: cfgr as *mut u32,
            cfgr_offset: ((N as usize) % 8) * 4,
            outdr: outdr as *mut u16,
        }
    }

    pub fn set_mode(&self, cnf: CNF, mode: MODE) {
        // let cnf_bit: u8 = match cnf {
        //     CNF::AnalogInput => 0b00,
        //     CNF::FloatingInput => 0b01,
        //     CNF::UpDownInput => 0b10,
        // };
        // let mode_bit = match mode {
        //     MODE::Input => 0b00,
        //     MODE::Mhz10 => 0b01,
        //     MODE::MHz2 => 0b10,
        //     MODE::MHz50 => 0b11,
        // };

        unsafe {
            //获取CFGR
            let mut current_cfgr = *self.cfgr;
            //设置MODE
            let range = self.cfgr_offset..(self.cfgr_offset + 2);
            current_cfgr.set_bits(self.cfgr_offset..(self.cfgr_offset + 2), mode as u32);
            //设置CNF
            current_cfgr.set_bits((self.cfgr_offset + 2)..(self.cfgr_offset + 4), cnf as u32);
            //写回CFGR
            *self.cfgr = current_cfgr;
        }
    }
}

impl<'a, const G: char, const N: u8> OutputPin for GPIO<'a, G, N> {
    #[inline(always)]
    fn set_low(&mut self) -> Result<(), Self::Error> {
        let temp = !(1u16 << N);
        unsafe {
            *self.outdr &= temp;
        }
        Ok(())
    }

    #[inline(always)]
    fn set_high(&mut self) -> Result<(), Self::Error> {
        let temp = 1u16 << N;
        unsafe {
            *self.outdr |= temp;
        }
        Ok(())
    }
}


impl<'a, const G: char, const N: u8> embedded_hal::digital::ErrorType for GPIO<'a, G, N> {
    type Error = embedded_hal::digital::ErrorKind;
}
